import gov.nih.mipav.view.ImageRegistryMonitor;
import gov.nih.mipav.view.ViewUserInterface;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

/**
 * Class containing all data necessary to obtain the segmentation
 * 
 * @author marco.zanger
 */
public class DataManager extends Module implements Drawable, MethodRelated,
    ActionListener, ChangeListener {

  /** Only one instance of this class is allowed. */
  private static DataManager instance = null;

  /** Manager to contain all the information related to the images. */
  private ImageManager imageManager;

  /** Manager to contain all the information related to the mask. */
  private MaskManager maskManager;

  /** Manager to contain all the information related to the initialPoints. */
  private InitialPointsManager ipManager;

  /**
   * Manager to contain all the information related to the variables affecting
   * the segmentation
   */
  private VariableManager variableManager;

  private DataManager() {
    super();
    imageManager = ImageManager.getInstance();
    maskManager = new MaskManager();
    ipManager = new InitialPointsManager();
    variableManager = new VariableManager();

    ImageRegistryMonitor imageMonitor = new ImageRegistryMonitor();
    imageMonitor.addImageRegistryChangeListener(this);
    imageMonitor.start();

    update();
  }

  public static DataManager getInstance() {
    if (instance == null)
      instance = new DataManager();
    return instance;
  }

  public Component drawContentPane() {
    JPanel dataPane = new JPanel();
    dataPane.setLayout(new BoxLayout(dataPane, BoxLayout.PAGE_AXIS));

    JButton updateButton = new JButton("update");
    updateButton.setActionCommand("UPDATE");
    updateButton.addActionListener(this);

    JPanel buttonPane = new JPanel();
    buttonPane.setLayout(new BorderLayout());
    buttonPane.add(updateButton);

    dataPane.add(imageManager.drawContentPane());
    dataPane.add(maskManager.drawContentPane());
    dataPane.add(ipManager.drawContentPane());
    dataPane.add(buttonPane);
    dataPane.add(variableManager.drawContentPane());

    return dataPane;
  }

  public void setEnable(boolean enable) {
    imageManager.setEnable(enable);
    maskManager.setEnable(enable);
    ipManager.setEnable(enable);
    variableManager.setEnable(enable);
  }

  protected void updateMe() {
    imageManager.update();
    maskManager.update();
    ipManager.update();
    RegionManager.getInstance().update();
    VOIManager.getInstance().update();
  }

  public void actionPerformed(ActionEvent event) {
    String command = event.getActionCommand();

    if (command.equals("UPDATE")) {
      update();
    }
  }

  public void updateProxy() {
    imageManager.updateProxy();
    maskManager.updateProxy();
    ipManager.updateProxy();
    variableManager.updateProxy();

    System.gc();
  }

  public ImageManager getImageManager() {
    return imageManager;
  }

  public MaskManager getMaskManager() {
    return maskManager;
  }

  public InitialPointsManager getInitialPointsManager() {
    return ipManager;
  }

  public VariableManager getVariableManager() {
    return variableManager;
  }

  @Override
  public void stateChanged(ChangeEvent arg0) {
    ViewUserInterface userInterface = ViewUserInterface.getReference();
    int numberOfImages = userInterface.getRegisteredImagesNum();
    if (numberOfImages != imageManager.getNumberOfImages())
      update();
  }

  @Override
  /**
   * * JSData must always send an update since it only calls the update for its
   * inner components.
   */
  public boolean needsToBeUpdated() {
    return true;
  }
}
